using System;
using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Serialization;
using UnityEngine.UI;

namespace WorkFlow.Tools.UI
{
    [ExecuteAlways]//上居中、上下居左、上下居右、FreeSpace
    public class CustomGridLayoutGroup : LayoutGroup
    {
        [SerializeField] protected bool horizontalStart = true;

        
        [SerializeField] protected Vector2 m_Spacing = Vector2.zero;
        [SerializeField] protected bool autoSize;
        //[SerializeField] [ShowIf("@!autoSize")][Header("限制行数或列数")] protected int limitHorOrVer = -1;
        [SerializeField] protected UnityEvent onUpdateLayoutBefore;
        public UnityEvent OnUpdateLayoutBefore => onUpdateLayoutBefore;
        /// <summary>
        /// The spacing to use between layout elements in the grid on both axes.
        /// </summary>
        public Vector2 spacing { get { return m_Spacing; } set { SetProperty(ref m_Spacing, value); } }
        
        public Vector2 FreeSpace { get; private set; }
        
        public float MaxWidth { get; private set; }
        
        public float MaxHeight { get; private set; }
        
        protected CustomGridLayoutGroup() {}

        #if UNITY_EDITOR
        protected override void OnValidate()
        {
            base.OnValidate();
        }
        #endif

        protected override void OnEnable()
        {
            base.OnEnable();
            ForceRefresh();
        }

        [Button]
        public void ForceRefresh()
        {
            CalculateLayoutInputHorizontal();
            CalculateLayoutInputVertical();
            SetLayoutHorizontal();
            //SetLayoutVertical();
            SetDirty();
        }
        
        
        public override void CalculateLayoutInputHorizontal()
        {
            onUpdateLayoutBefore?.Invoke();
            base.CalculateLayoutInputHorizontal();
            SetLayoutInputForAxis(0, rectTransform.rect.width, -1, 0);
        }

        public override void CalculateLayoutInputVertical()
        {
            SetLayoutInputForAxis(0, rectTransform.rect.height, -1, 1);
        }

        public void RefreshFreeSpace()
        {
            SetLayoutHorizontal();
        }
        
        public override void SetLayoutHorizontal()
        {
            SetCellsAlongAxis(0);
        }

        public override void SetLayoutVertical()
        {
            SetCellsAlongAxis(1);
        }

        private List<RectTransform> _lineRectChildren;
        private List<Vector2> _lineRectChildrenPos;
        
        private void SetCellsAlongAxis(int axis)
        {
            if (axis == 1) return;
            if (horizontalStart)
            {
                if (childAlignment == TextAnchor.UpperLeft)
                {
                    // Set horizontal positions
                    float xPos = padding.left;
                    float yPos = padding.top;
                    float currentMaxHeight = 0;
                    foreach (var rectChild in rectChildren)
                    {
                        if (xPos + rectChild.rect.width + padding.right > rectTransform.rect.width)
                        {
                            xPos = padding.left;
                            yPos += currentMaxHeight + spacing.y;
                            currentMaxHeight = rectChild.rect.height;
                        }
                        else
                        {
                            currentMaxHeight = Mathf.Max(currentMaxHeight, rectChild.rect.height);
                        }

                        SetChildAlongAxis(rectChild, 0, xPos);
                        SetChildAlongAxis(rectChild, 1, yPos);
                        xPos += rectChild.rect.width + spacing.x;
                    }
                    MaxHeight = currentMaxHeight;
                    if (autoSize)
                        rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical,
                            yPos + padding.bottom + currentMaxHeight);
                    FreeSpace = new Vector2(
                        rectTransform.rect.width - (xPos + padding.right + spacing.x),
                        rectTransform.rect.height - (yPos + padding.bottom + spacing.y));
                }
                else if (childAlignment == TextAnchor.UpperRight)
                {
                    // Set horizontal positions
                    float xPos = rectTransform.rect.width - padding.right;
                    float yPos = padding.top;
                    float currentMaxHeight = 0;
                    int lastlineNumber = -1;
                    int currentLineNumber = 0;
                    foreach (var rectChild in rectChildren)
                    {
                        xPos -= rectChild.rect.width;
                        if (xPos < 0 && currentLineNumber == lastlineNumber) //换行
                        {
                            xPos = rectTransform.rect.width - padding.right - rectChild.rect.width;
                            yPos += currentMaxHeight + spacing.y;
                            currentMaxHeight = rectChild.rect.height;
                        }
                        else
                        {
                            currentMaxHeight = Mathf.Max(currentMaxHeight, rectChild.rect.height);
                        }

                        lastlineNumber = currentLineNumber;
                        SetChildAlongAxis(rectChild, 0, xPos);
                        SetChildAlongAxis(rectChild, 1, yPos);
                        xPos -= spacing.x;
                    }
                    MaxHeight = currentMaxHeight;
                    if (autoSize)
                        rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical,
                            yPos + padding.bottom + currentMaxHeight);
                    FreeSpace = new Vector2(
                        (xPos - padding.right - spacing.x),
                        rectTransform.rect.height - (yPos + padding.bottom + spacing.y));
                }
                else if (childAlignment == TextAnchor.UpperCenter)
                {
                        //实现UppterCenter布局
                        // Set horizontal positions for UpperCenter alignment
                        float xPos = padding.left;
                        float yPos = padding.top;
                        float currentMaxHeight = 0;

                        if (_lineRectChildren == null)
                        {
                            _lineRectChildren = new List<RectTransform>();
                            _lineRectChildrenPos = new List<Vector2>();
                        }
                        else
                        {
                            _lineRectChildren.Clear();
                            _lineRectChildrenPos.Clear();
                        }

                        float currentLineWidth = 0;
                        
                        foreach (var rectChild in rectChildren)
                        {
                            if (xPos + rectChild.rect.width + padding.right > rectTransform.rect.width)
                            {
                                SetLineRectTransformOffsetX(currentLineWidth);
                                currentLineWidth = 0;
                                xPos = padding.left;
                                yPos += currentMaxHeight + spacing.y;
                                currentMaxHeight = rectChild.rect.height;
                            }
                            else
                            {
                                currentMaxHeight = Mathf.Max(currentMaxHeight, rectChild.rect.height);
                            }

                            currentLineWidth += rectChild.rect.width;
                            _lineRectChildren.Add(rectChild);
                            _lineRectChildrenPos.Add(new Vector2(xPos,yPos));
                            SetChildAlongAxis(rectChild, 0, xPos);
                            SetChildAlongAxis(rectChild, 1, yPos);
                            xPos += rectChild.rect.width + spacing.x;
                        }
                        SetLineRectTransformOffsetX(currentLineWidth);
                        if (autoSize)
                            rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical,
                                yPos + padding.bottom + currentMaxHeight);
                        FreeSpace = new Vector2(
                            (xPos - padding.right - spacing.x),
                            rectTransform.rect.height - (yPos + padding.bottom + spacing.y));
                }
            }
            else
            {
                if (childAlignment == TextAnchor.UpperLeft)
                {
                    // Set vertical positions
                    float xPos = padding.left;
                    float yPos = padding.top;
                    float currentMaxWidth = 0;
                    foreach (var rectChild in rectChildren)
                    {
                        if(yPos + rectChild.rect.height + padding.bottom > rectTransform.rect.height)
                        {
                            yPos = padding.top;
                            xPos += currentMaxWidth + spacing.x;
                            currentMaxWidth = rectChild.rect.width;
                        }
                        else
                        {
                            currentMaxWidth = Mathf.Max(currentMaxWidth, rectChild.rect.width);
                        }
                        SetChildAlongAxis(rectChild, 0, xPos);
                        SetChildAlongAxis(rectChild, 1, yPos);
                        yPos += rectChild.rect.height + spacing.y;
                    }
                    MaxWidth = currentMaxWidth;
                    if(autoSize)
                        rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, xPos + padding.right + currentMaxWidth);
                    //TODO 计算剩余空间
                }
                else  if (childAlignment == TextAnchor.UpperRight)
                {
                    // Set vertical positions
                    float xPos = rectTransform.rect.width - padding.right;
                    float yPos = padding.top;
                    float currentMaxWidth = 0;
                    foreach (var rectChild in rectChildren)
                    {
                        if(yPos + rectChild.rect.height + padding.bottom > rectTransform.rect.height)
                        {
                            yPos = padding.top;
                            xPos -= currentMaxWidth + spacing.x;
                            currentMaxWidth = rectChild.rect.width;
                        }
                        else
                        {
                            currentMaxWidth = Mathf.Max(currentMaxWidth, rectChild.rect.width);
                        }
                        SetChildAlongAxis(rectChild, 0, xPos - rectChild.rect.width);
                        SetChildAlongAxis(rectChild, 1, yPos);
                        yPos += rectChild.rect.height + spacing.y;
                    }
                    MaxWidth = currentMaxWidth;
                    if(autoSize)
                        rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, -xPos + currentMaxWidth + padding.left);
                    //TODO 计算剩余空间 
                }
            }
        }
        
        private void SetLineRectTransformOffsetX(float rectChildrenWidth)
        {
            float lineSpacing = (rectTransform.rect.width -
                                 rectChildrenWidth - padding.left - padding.right -
                                 (_lineRectChildren.Count - 1) * spacing.x) / 2;
            for(int i = 0; i < _lineRectChildren.Count; i++)
            {
                var lineRectChild = _lineRectChildren[i];
                var pos = _lineRectChildrenPos[i];
                SetChildAlongAxis(lineRectChild, 0, pos.x + lineSpacing);
                SetChildAlongAxis(lineRectChild, 1, pos.y);
            }
            _lineRectChildren.Clear();
            _lineRectChildrenPos.Clear();
        }
    }
}